#include "TaskManager.h"

//Initializes the TaskManager class with a current task reference
//number of 1.
TaskManager::TaskManager() {
	currTaskRef = 1;
	logger.setFileName(FILE_NAME_TASK_MANAGER_LOGGER);
}

//This function calls parser class to parse user input, determines the appropriate task
//and calls the appropriate functions to create and return the task. User inputs are
//handled as references so that as the string cascades through the processing functions,
//the information already processed is removed.
Task TaskManager::create(QString &parameters) {
	string logInfo = "user input parsed: " + parameters.toStdString();
	logger.logInfo(logInfo);

	Task::TaskType taskType = parser.determineTask(parameters);
	switch (taskType) {
		case Task::FLOATING: return processFloating(parameters);
		case Task::DEADLINE: return processDeadline(parameters);
		case Task::MEETING: return processMeeting(parameters);
		case Task::EVENT: return processEvent(parameters);
		default:
			throw InvalidInputException("unrecognized error. ");
	};
}

//This function loads the session by creating a vector of tasks. It takes in an ostringstream
//reference containing all the stored information in the file and a reference to a vector of 
//strings that are populated with invalid task strings that could not be processed. Contains
//relevant guards for exceptions that occur during task creation and pushes them into the
//vector of invalid strings.

//If the task contains the "*" special character that indicates completion, it will initialize
//the task as complete before pushing it into the vector of tasks.
QVector<Task> TaskManager::loadSession(ostringstream &sessionInfo, QVector<QString> &invalidTasks) {
	string logInfo = MESSAGE_USER_INPUT + sessionInfo.str();
	logger.logInfo(logInfo);

	string taskDetails = sessionInfo.str();
	QVector<Task> loadedTasks;
	int pos = 0;

	while (pos != string::npos) {
		pos = taskDetails.find_first_of("\n");
		
		QString currTaskParam = QString::fromStdString(taskDetails.substr(0, pos));
		QString invalidTaskParam = currTaskParam;
		Task task;

		try {
			task = create(currTaskParam);
		} catch(InvalidInputException &e) {
			QString userFeedback = e.what();
			userFeedback += MESSAGE_INVALID_INPUT;
			task.setTitle(userFeedback);
			logger.logInfo(userFeedback.toStdString());
		}

		if (parser.parseComplete(currTaskParam)) {
			task.markComplete();
		}

		if (task.getTitle() != "") {
			if (task.getTitle().contains(MESSAGE_INVALID)) {
				loadedTasks.push_back(task);
			}
			else {
				invalidTaskParam = task.getTitle() + invalidTaskParam; 
				invalidTasks.push_back(invalidTaskParam);
			}
		}
				
		taskDetails = taskDetails.substr(pos + 1);
	}

	return loadedTasks;
}

//Returns a floating task.
Task TaskManager::createTask(QString setTitle, QDateTime setStartDate, QDateTime setEndDate,
							 QVector<QString> setTags) {
	Task setTask;

	setTask.setTask(currTaskRef, setTitle, setStartDate, setEndDate, setTags);
	currTaskRef++;

	return setTask;
}

//Processes and returns a floating task.
Task TaskManager::processFloating(QString &parameters) {
	QString title;
	QDateTime start, end;
	QVector<QString> tags;

	title = parser.retrieveParam(Task::FLOATING, parameters);

	return createTask(title, start, end, tags);
}

//Extracts the relevant task parameters, processes and returns a deadline.
Task TaskManager::processDeadline(QString &parameters) {
	QString title, date;
	QDateTime start, end;
	QVector<QString> tags;

	title = parser.retrieveParam(Task::DEADLINE, parameters);
	date = parser.retrieveParam(Task::DEADLINE, parameters);
	
	QDate endDate = parser.parseDate(date);
	QTime endTime = parser.parseTime(parameters);
	
	end.setDate(endDate);
	end.setTime(endTime);

	return createTask(title, start, end, tags);
}

//Extracts the relevant task parameters, processes and returns a meeting.
Task TaskManager::processMeeting(QString &parameters) {
	QString title, date, time;
	QDateTime start, end;
	QVector<QString> tags;
		
	title = parser.retrieveParam(Task::MEETING, parameters);
	date = parser.retrieveParam(Task::MEETING, parameters);
	time = parser.retrieveParam(Task::MEETING, parameters);
	
	QDate taskDate = parser.parseDate(date);
	QTime startTime = parser.parseTime(time);
	QTime endTime = parser.parseTime(parameters);

	if (endTime < startTime) {
		string errorMessage = "invalid timing, start time occurs after end time. ";
		string logInfo = MESSAGE_USER_INPUT + errorMessage;
		logger.logInfo(logInfo);
		throw InvalidInputException(errorMessage);
	}

	start.setDate(taskDate);
	start.setTime(startTime);
	end.setDate(taskDate);
	end.setTime(endTime);

	return createTask(title, start, end, tags);
}

Task TaskManager::processEvent(QString &parameters) {
	QString title, startDateStr, startTimeStr, endDateStr;
	QDateTime start, end;
	QVector<QString> tags;
		
	title = parser.retrieveParam(Task::EVENT, parameters);
	startDateStr = parser.retrieveParam(Task::EVENT, parameters);
	startTimeStr = parser.retrieveParam(Task::EVENT, parameters);
	endDateStr = parser.retrieveParam(Task::EVENT, parameters);
	
	QDate startDate = parser.parseDate(startDateStr);
	QTime startTime = parser.parseTime(startTimeStr);
	QDate endDate = parser.parseDate(endDateStr);
	QTime endTime = parser.parseTime(parameters);

	start.setDate(startDate);
	start.setTime(startTime);
	end.setDate(endDate);
	end.setTime(endTime);


	if (end < start) {
		string errorMessage = "invalid timing, start time occurs after end time. ";
		string logInfo = MESSAGE_USER_INPUT + errorMessage;
		logger.logInfo(logInfo);
		throw InvalidInputException(errorMessage);
	}

	return createTask(title, start, end, tags);
}